--[=[

]=]

--require "util"
-- require "GameDefine"
require "luaext"

--牌数
HAND_CARD_COUNT             = 3

--牌背值
BACK_CARD = 0
--金花牌型
CardType =
{
    NoShow = 0, --不展示类型
    HighCard = 1, --高牌
    OnePair = 2, --对子
    Straight = 3, --顺子
    Flush = 4, --金花
    FlushStraight = 5, --顺金
    ThreeOfAKind = 6, --豹子
    Special = 0x100, --特殊牌型,花色不同的235
}

--牌型名称
CardTypeName =
{
    [CardType.NoShow] = "不展示",
    [CardType.HighCard]     = "高牌",
    [CardType.OnePair]      = "对子",
    [CardType.Straight]      = "顺子",
    [CardType.Flush]    = "金花",
    [CardType.FlushStraight]     = "顺金",
    [CardType.ThreeOfAKind]     = "豹子",
    [CardType.Special]      = "特殊牌型",
}

local GameRule = class("GameRule")


-- 构造函数
function GameRule:ctor()
	--随机种子
	math.randomseed()
	self.init_cards = --扑克牌说明，0xAB, (A为花色 3黑桃 2红桃 1梅花 0方块)，B为点数1-13为A-K
	{
		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d,
		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d,
		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d,
		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d
	}

	--扑克颜色
	self.CardColor =
	{
		Mask    = 0xF0,     --掩码
		Diamond = 0x00,     --方块
		Club    = 0x10,     --梅花
		Heart   = 0x20,     --红心
		Spade   = 0x30,     --黑桃
		King    = 0x40,     --王
	}
	self.CardColorName =
	{
		[self.CardColor.Diamond] = "♦",
		[self.CardColor.Club] = "♣",
		[self.CardColor.Heart] = "♥",
		[self.CardColor.Spade] = "♠",
		[self.CardColor.King] = "王牌",
	}
	self.CardValueName =
	{ "A","2","3", "4", "5", "6", "7", "8", "9", "10", "J", "Q","K" }

	--扑克数值
	self.CardValue =
	{
		Mask    = 0x0F,     --掩码
		MaxCard = 0x0e, --最大牌值
	}

	--牌型权重基值 高牌，一对，顺子，同花，同花顺，三条
	self.CardWeight =
	{
		CardThree =100,--最小牌权重
		CardTwo = 1000, --次张牌权重
		CardOne =10000, --最大牌的权重
		HighCard = 0x10000, --高牌
		OnePair = 0x20000, --对子
		Straight = 0x30000, --顺子
		Flush = 0x40000, --同花
		FlushStraight = 0x50000, --同花顺
		ThreeOfAKind = 0x60000, --三条
	}
	
	--牌类型
	self.CardType = {}
	for k, v in pairs(CardType) do
		self.CardType[k] = v
	end

	--牌类型名称
	self.CardTypeName = {}
	for k, v in pairs(CardTypeName) do
		self.CardTypeName[k] = v
	end

	--发牌数据
	self.cards = {}
end

--获取牌花色
function GameRule:getCardColor(card)
	return (card & self.CardColor.Mask)
end

--获取牌数值
function GameRule:getCardValue(card)
	return (card & self.CardValue.Mask)
end

--获取牌逻辑值
function GameRule:getCardLogicValue(card)
	local card_value = (card & self.CardValue.Mask)
	if card_value <= 10 then
		return card_value
	else
		return 10
	end
end

--洗牌
function GameRule:shuffle()
	for k, v in pairs(self.init_cards) do
		self.cards[k] = v
	end
	table.mix(self.cards)
end

-- 排序扑克
function GameRule:sortCard(cards,card_type)
	cards = cards or {}
	for i=1, #cards do
		if (card_type and card_type ~=self.CardType.FlushStraight and
				card_type ~=self.CardType.Straight  and
				self:getCardValue(cards[i]) == 0x01) then
			cards[i] =cards[i] + self.CardValue.MaxCard
		end
	end

	local function compare(card1, card2)
		local card_value1 = self:getCardValue(card1)
		local card_value2 = self:getCardValue(card2)

		if card_value1 ~= card_value2 then
			return card_value1 > card_value2
		end

		local card_color1 = self:getCardColor(card1)
		local card_color2 = self:getCardColor(card2)
		return card_color1 > card_color2
	end
	table.sort(cards, compare)
end

--取牌
function GameRule:getCards(card_count)
	local cards = {}
	local n = card_count or 0
	for k, v in pairs(self.cards) do
		if n <= 0 then break end
		if v then
			n = n - 1
			table.insert(cards, v)
			self.cards[k] = nil
		end
	end
	return cards
end

--把牌放到最后
function GameRule:pushCard(card)
	table.insert(self.cards, card)
end

function GameRule:isSpecial(card_type)
	if not card_type then
		return false
	end
	return card_type & self.CardType.Special == self.CardType.Special
end

function GameRule:getRealCardType(card_type)
	if not card_type then
		return false
	end
	return card_type & ~self.CardType.Special
end

--通过权重取牌型值
function GameRule:getCardType(_cards)
	_cards = _cards or {}
	local cards =table.deepcopy(_cards)
	if #cards ~= HAND_CARD_COUNT then
		return self.CardType.NoShow
	end

	self:sortCard(cards)

	local card1=self:getCardValue(cards[1])
	local card2=self:getCardValue(cards[2])
	local card3=self:getCardValue(cards[3])

	--三条
	if card1 == card2 and card1 == card3 then
		return self.CardType.ThreeOfAKind
	end

	--是否是顺子
	local function isStraight(card1,card2,card3)
		if (card1  == card2 + 1 and
				card2 == card3 + 1) then
			return true
		end
		return false
	end

	--是否是同花
	local function isFlush(suit1,suit2,suit3)
		if (suit1  == suit2  and
				suit1 == suit3 ) then
			return true
		end
		return false
	end

	--是否是同花或者顺子
	local function isStraightOrFlush(cards)
		local card1=self:getCardValue(cards[1])
		local card2=self:getCardValue(cards[2])
		local card3=self:getCardValue(cards[3])
		local suit1=self:getCardColor(cards[1])
		local suit2=self:getCardColor(cards[2])
		local suit3=self:getCardColor(cards[3])

		--同花顺
		if (isFlush(suit1,suit2,suit3) and
					isStraight(card1,card2,card3)) then
			return self.CardType.FlushStraight
		end
		--同花
		if isFlush(suit1,suit2,suit3) then
			return self.CardType.Flush
		end
		--顺子
		if isStraight(card1,card2,card3) then
			return self.CardType.Straight
		end
	end
	--同花或者顺子
	local card_type =isStraightOrFlush(cards)
	if card_type then
		return card_type
	end

	--一对
	if card1 ~= card3 and (card1 == card2 or
			card2 == card3) then
		return self.CardType.OnePair
	end

	--特殊牌型235，只有在比牌的时候才能确定真实牌型
	if (card1== 5 and card2 == 3
				and card3 ==2) then
		return self.CardType.Special | self.CardType.HighCard
	end

	return self.CardType.HighCard
end


--获取牌类型名称
function GameRule:getCardTypeName(card_type)
	return self.CardTypeName[card_type]
end

--比牌大小
function GameRule:compareCard(_first_cards, _next_cards)
	local first_cards =table.deepcopy(_first_cards)
	local next_cards =table.deepcopy(_next_cards)
	if #first_cards ~= #next_cards then
		assert(false)
		return 0
	end

	local first_card_type = self:getCardType(first_cards)
	local next_card_type = self:getCardType(next_cards)

	--特殊牌型 235<===>三条
	if (self:isSpecial(first_card_type) and
			next_card_type ==self.CardType.ThreeOfAKind ) then
		return -1
	end
	if (self:isSpecial(next_card_type) and
			first_card_type ==self.CardType.ThreeOfAKind ) then
		return 1
	end

	--还原真实的牌值类型
	first_card_type =self:getRealCardType(first_card_type)
	next_card_type =self:getRealCardType(next_card_type)
	--比较牌型
	if first_card_type ~= next_card_type then
		if first_card_type < next_card_type then
			return 1
		else
			return -1
		end
	else
		self:sortCard(first_cards,first_card_type)
		self:sortCard(next_cards,next_card_type)
		--[[
			再同一牌型的情况下，先根据牌值权重计算3张牌的总得分,再进行比较,
			在得分相同的情况下，计算最大牌的花色
		]]
		local function getCardsScore(cards)
			local card_value1=self:getCardValue(cards[1])
			local card_value2=self:getCardValue(cards[2])
			local card_value3=self:getCardValue(cards[3])

			return (card_value1 * self.CardWeight.CardOne +
					card_value2	* self.CardWeight.CardTwo +
					card_value3 * self.CardWeight.CardThree)
		end

		local first_score =getCardsScore(first_cards)
		local next_score  =getCardsScore(next_cards)
		if first_score < next_score then
			return 1
		elseif first_score > next_score then
			return -1
		else
			local first_card_color = self:getCardColor(first_cards[1])
			local next_card_color = self:getCardColor(next_cards[1])
			--比较牌花色
			if first_card_color < next_card_color then
				return 1
			elseif first_card_color > next_card_color then
				return -1
			else
				return 0
			end
		end
	end

	return 0
end




--输出16进制牌
function GameRule:printCard(cards)
	--print("----",cards)
	local str = ""
	for k, v in pairs(cards) do
		local suit = v & self.CardColor.Mask
		local value = v & self.CardValue.Mask
		value = value % self.CardValue.MaxCard
		--print("suit","value",suit,value)
		if str=="" then 
			str = self.CardColorName[suit]..self.CardValueName[value]
		else
			str = str..', '..self.CardColorName[suit]..self.CardValueName[value]
		end
		--str = str..', ' .. string.format("%02x", v)
	end
	return str
	--print(str)
end


return GameRule

